//------------------------------------------------------------------------------
///
///	\file sm-full.c
///
///	\brief
///		State Machine full test
///
//	$Id: sm-full.c 330 2015-02-02 05:57:58Z ac.verbeck@gmail.com $
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//	The MIT License (MIT)
//
//	Copyright (c) 2014 A.C. Verbeck
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.

//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdint.h>									//	Standard int types
#include <stdbool.h>								//	Bool

#include "sm.h"
#include "debug.h"

//------------------------------------------------------------------------------
// Local enum
//------------------------------------------------------------------------------
enum {ST_STANDBY, ST_RUN, ST_MENU, ST_DISPLAY, ST_CT	};

//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
static SM_STATE sm_test_init(STATE_MACHINE* sm);

static SM_STATUS s0_st_enter(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s0_st_process(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s0_st_exit(STATE_MACHINE* sm, SM_EVENT ev);

static SM_STATUS s1_st_enter(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s1_st_process(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s1_st_exit(STATE_MACHINE* sm, SM_EVENT ev);

static SM_STATUS s2_st_enter(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s2_st_process(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s2_st_exit(STATE_MACHINE* sm, SM_EVENT ev);

static SM_STATUS s3_st_enter(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s3_st_process(STATE_MACHINE* sm, SM_EVENT ev);
static SM_STATUS s3_st_exit(STATE_MACHINE* sm, SM_EVENT ev);

//------------------------------------------------------------------------------
// Local data
//------------------------------------------------------------------------------
static const SM_STATE_FN states[] = {
	[ST_STANDBY]	= {	s0_st_enter,	s0_st_process,		s0_st_exit		},	//	state: s0 -- standby state
	[ST_RUN]		= {	s1_st_enter,	s1_st_process,		s1_st_exit		},	//	state: s1 -- run state
	[ST_MENU]		= {	s2_st_enter,	s2_st_process,		s2_st_exit		},	//	state: s2 -- menu state
	[ST_DISPLAY]	= {	s3_st_enter,	s3_st_process,		s3_st_exit		},	//	state: s3 -- display state
};
static const uint32_t sm_state_ct = sizeof(states)/sizeof(SM_STATE_FN);

static STATE_MACHINE sm = {
	.PrevState		= ST_STANDBY,												//	Previous state
	.CurrState		= ST_STANDBY,												//	Curr state
	.NewState		= ST_STANDBY,												//	Set full state to same as curr state
	.Status			= SM_OK,													//	status
	.StateChange	= false,													//	Changing states: nope
	.InitFn			= sm_test_init,												//	fn: initialization
};

//------------------------------------------------------------------------------
//	@brief
//		Next test state machine
//		Init the state machine
//
//	@param
//		none
//
//	@return
//		none
//------------------------------------------------------------------------------
void sm_full_init(void)
{
	SM_Init(&sm, states, sm_state_ct);
}

//------------------------------------------------------------------------------
//	@brief
//		Next test state machine
//		Run the state machine -- process incoming events
//
//	@param
//		int ev:	incoming event
//
//	@return
//		none
//------------------------------------------------------------------------------
void sm_full_process(int ev)
{
	SM_Process(&sm, states, (SM_EVENT)ev);										//	Process current state
}

//------------------------------------------------------------------------------
//	@brief
//		State machine state processing
//		Initialize the state machine, return the first state
//
//	@param
//		sm:	state machine
//		ev:	state machine event
//
//	@return
//		state machine first state
//------------------------------------------------------------------------------
static SM_STATE sm_test_init(STATE_MACHINE* sm)
{
	TRACE(INFO, "full state machine test");
	return ST_STANDBY;
}

//------------------------------------------------------------------------------
//	@brief
//		State machine state processing
//		S0 state processing: This is the standby state.
//		- s0_st_enter:		enter state
//		- s0_st_process:	process state
//		- s0_st_exit:		exit state
//
//	@param
//		sm:	state machine
//		ev:	state machine event
//
//	@return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s0_st_enter(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "standby enter");												//	Standby state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s0_st_process(STATE_MACHINE* sm, SM_EVENT ev)
{
	if (ev == 'p') {
		SM_StateChange(sm, ST_RUN);												//	Change to run state
		printf("\npower key: state change to run\n");							//	Note it
	} else
		printf("%c ",ev);														//	Display it

	TRACE(INFO,"standby process");												//	Display state processing
	return SM_OK;																//	Status is OK
}
static SM_STATUS s0_st_exit(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "standby exit");												//	Standby state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	@brief
//		State machine state processing
//		S1 state processing: This is the run state.
//		- s1_st_enter:		enter state
//		- s1_st_process:	process state
//		- s1_st_exit:		exit state
//
//	@param
//		sm:	state machine
//		ev:	state machine event
//
//	@return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s1_st_enter(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "run enter");													//	Run state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s1_st_process(STATE_MACHINE* sm, SM_EVENT ev)
{
	switch (ev) {
	case 'p':
		SM_StateChange(sm, ST_STANDBY);											//	Change to standby state
		printf("\npower key: state change to standby\n");						//	Note it
		break;																	//	p = power event
	case 'm':
		SM_StateChange(sm, ST_MENU);											//	Change to menu state
		printf("\nmenu key: state change to OSD on\n");							//	Note it
		break;																	//	m = menu event
	case 'd':
		SM_StateChange(sm, ST_DISPLAY);											//	Change to display state
		printf("\ndisplay key: state change to display\n");						//	Note it
		break;																	//	d = display event
	default:
		printf("%c ",ev);														//	Display it
		break;																	//	default is button
	}

	TRACE(INFO,"run process");													//	Display state processing
	return SM_OK;																//	Status is OK
}
static SM_STATUS s1_st_exit(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "run exit");													//	Run state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	@brief
//		State machine state processing
//		S2 state processing: This is the menu state.
//		- s2_st_enter:		enter state
//		- s2_st_process:	process state
//		- s2_st_exit:		exit state
//
//	@param
//		sm:	state machine
//		ev:	state machine event
//
//	@return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s2_st_enter(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "menu enter");													//	Menu state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s2_st_process(STATE_MACHINE* sm, SM_EVENT ev)
{
	switch (ev) {
	case 'p':
		SM_StateChange(sm, ST_STANDBY);											//	Change to standby state
		printf("\npower key: state change to standby\n");						//	Note it
		break;																	//	p = power event
	case 'r':
		SM_StateChange(sm, ST_RUN);												//	Change to run state
		printf("\nrun key: state change to run\n");								//	Note it
		break;																	//	r = power event
	case 'm':
		SM_StatePrev(sm);														//	Change to previous state
		printf("\nmenu key: state change to previous state\n");					//	Note it
		break;																	//	m = menu event
	case 'd':
		SM_StateChange(sm, ST_DISPLAY);											//	Change to display state
		printf("\ndisplay key: state change to display\n");						//	Note it
		break;																	//	d = display event
	default:
		printf("%c ",ev);														//	Display it
		break;																	//	default is button
	}

	TRACE(INFO,"menu process");													//	Display state exit
	return SM_OK;																//	Status is OK
}
static SM_STATUS s2_st_exit(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "menu exit");													//	Menu state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	@brief
//		State machine state processing
//		S3 state processing: This is a null state.
//		- s3_st_enter:		enter state
//		- s3_st_process:	process state
//		- s3_st_exit:		exit state
//
//	@param
//		sm:	state machine
//		ev:	state machine event
//
//	@return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s3_st_enter(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "display enter");												//	Display state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s3_st_process(STATE_MACHINE* sm, SM_EVENT ev)
{
	switch (ev) {
	case 'p':
		SM_StateChange(sm, ST_STANDBY);											//	Change to standby state
		printf("\npower key: state change to standby\n");						//	Note it
		break;																	//	p = power event
	case 'r':
		SM_StateChange(sm, ST_RUN);												//	Change to run state
		printf("\nrun key: state change to run\n");								//	Note it
		break;																	//	r = power event
	case 'm':
		SM_StateChange(sm, ST_MENU);											//	Change to menu state
		printf("\nmenu key: state change to run\n");							//	Note it
		break;																	//	m = menu event
	case 'd':
		SM_StatePrev(sm);														//	Change to previous state
		printf("\ndisplay key: state change to previous state\n");				//	Note it
		break;																	//	d = display event
	default:
		printf("%c ",ev);														//	Display it
		break;																	//	default is button
	}

	TRACE(INFO,"display process");												//	Display state exit
	return SM_OK;																//	Status is OK
}
static SM_STATUS s3_st_exit(STATE_MACHINE* sm, SM_EVENT ev)
{
	TRACE(INFO, "display exit");												//	Display state exit
	return SM_OK;																//	Status is OK
}

//
//  End: sm-full.c
//
